package file
{
	import flash.events.Event;
	import flash.filesystem.File;
	import flash.filesystem.FileMode;
	import flash.filesystem.FileStream;
	
	/**
	 * REQUIREMENTS: SDK v4.1 AIR 2.0
	 * class for implementing file access functions
	 * making it more easy to use files in AIR/FLEX/AS3
	 * 
	 * HOW TO USE IT:
	 * 1. import: in your mxml type:
	 * 
	 *    import toolBox.AIR_FILEACCESS_class;
	 * 
	 * 2. new instance: create a new copy of the class-object in ram
	 * 
	 *    var AIR_FILEACCESS_class_instance:AIR_FILEACCESS_class = new AIR_FILEACCESS_class();
	 * 
	 * 3. register event listener for asynchronous read/write operations (required if one wants to use asynchronous reading/writing/streaming)
	 * 
	 * 	  AIR_FILEACCESS_class_instance.addEventListener(Event.COMPLETE, FUNCTION_THAT_WILL_START_WHEN_FILE_OPERATION_IS_COMPLETE);

 			// EXAMPLE functions handles events during asynchronous file operations
			public function FUNCTION_handle_asynchronous_read_results(event:Event):void
			{
			
			}
			 
	 *    most read/write operations are asynchronous per default,
     *    this has the advantage,
	 *    that ur program does not have to stop execution when while loading is done in progress in the background.
	 * 
	 * 4. show load/save progress
 			AIR_FILEACCESS_class_instance.addEventListener(Event.COMPLETE, FUNCTION_handle_asynchronous_read_results);
			AIR_FILEACCESS_class_instance.addEventListener(IOErrorEvent.IO_ERROR, FUNCTION_handle_asynchronous_read_results);
			AIR_FILEACCESS_class_instance.addEventListener(OutputProgressEvent.OUTPUT_PROGRESS, FUNCTION_handle_asynchronous_read_results);

	 * **/
	public class air_file_access extends FileStream
	{
		/** initialise **/
		public function AIR_FILEACCESS_class()
		{
		}
		
		/** reads XML files that has the following format:
		 * 
			<?xml version="1.0" encoding="utf-8"?>
			<root>
				<test property="some property"/>
				<test>test</test>
			</root>
		 *
		 * STRING_Path_and_Name_of_File
		 * 		this can be relative path (starting point is directory in which the the AIR-application resides)
		 *		or absolute path
		 * 
		 * STRING_absolute_or_relative_path
		 * 		absolute
		 * 		relative
		 * 
		 * STRING_synchronous_or_asynchronous
		 * 		asynchronous -> read file really as a stream... and continue progamm execution in background, fire Event.COMPLETE when file loading complete.
		 * 		synchronous -> stop programm execution until file is fully loaded.
		 * 
		 * returns XML Object: the XML-interpretation of the file as object with tags and properties
		**/
		public function FUNCTION_FILE_readXML(STRING_Path_and_Name_of_File:String,STRING_absolute_or_relative_path:String,STRING_synchronous_or_asynchronous:String = 'asynchronous'):XML
		{
			var file_inst:File = new File();
			
			if(STRING_absolute_or_relative_path == 'absolute')
			{
				file_inst = file_inst.resolvePath(STRING_Path_and_Name_of_File);
			}
			
			if(STRING_absolute_or_relative_path == 'relative')
			{
				file_inst = File.applicationDirectory; // The folder containing the application's installed files.
				file_inst = File.applicationDirectory.resolvePath(STRING_Path_and_Name_of_File);
			}
			
			var XML_Result:XML = new XML();
	
			if(file_inst.exists && file_inst.isDirectory == false)
			{
				// var fileStream:FileStream = new FileStream();
				this.open(file_inst, FileMode.READ); // open in read mode
				
				XML_Result = XML(this.readUTFBytes(this.bytesAvailable));

				this.close();
				// Call the close() method of the FileStream object when you are done working with the file_inst.
				// This makes the file_inst available to other applications.
			}
			
			return XML_Result;
		}
		
		public function FUNCTION_FILE_readXML_fromFile(file_inst:File,STRING_synchronous_or_asynchronous:String = 'asynchronous'):XML
		{
			var XML_Result:XML = new XML();
	
			if(file_inst.exists && file_inst.isDirectory == false)
			{
				// var fileStream:FileStream = new FileStream();
				this.open(file_inst, FileMode.READ); // open in read mode
				
				XML_Result = XML(this.readUTFBytes(this.bytesAvailable));
				
				this.close();
				// Call the close() method of the FileStream object when you are done working with the file_inst.
				// This makes the file_inst available to other applications.
			}
			
			return XML_Result;
		}
		
		/** reads a utf-8 text file_inst, of which u know the path+filename
		 * 
		 * STRING_Path_and_Name_of_File
		 * 		this can be relative path (starting point is directory in which the the AIR-application resides)
		 *		or absolute path
		 * 
		 * STRING_absolute_or_relative_path
		 * 		absolute
		 * 		relative
		 * 
		 * returns
		 * OBJECT_Result['string'] = the whole text as string.
		 * OBJECT_Result['lines'] = one array-element is one line is in text file_inst.
		 * OBJECT_Result['exists'] = either true or false
		 * OBJECT_Result['type'] = file_inst type, currently this function detects the following file_inst types:
		 * 							directory, 
	 	 * STRING_synchronous_or_asynchronous
		 * 		synchronous -> stop programm execution until file_inst is fully loaded.
		 * 		asynchronous -> (default) read file_inst really as a stream... and continue progamm execution in background, fire Event.COMPLETE when file_inst loading complete.
		 * 			when reading asynchronously one must register a event listener which then continues processing the read data.
		**/
		public function FUNCTION_FILE_readUTF8_fromPath(STRING_Path_and_Name_of_File:String = '',STRING_absolute_or_relative_path:String = '',STRING_synchronous_or_asynchronous:String = 'asynchronous'):Object
		{
			var OBJECT_Result:Object = {string:'',lines:new Array(),exists:Boolean,type:''};
			
			var file_inst:File = new File();
			if(STRING_absolute_or_relative_path == 'absolute')
			{
				file_inst = file_inst.resolvePath(STRING_Path_and_Name_of_File);
			}
			
			if(STRING_absolute_or_relative_path == 'relative')
			{
				file_inst = File.applicationDirectory; // The folder containing the application's installed files.
				file_inst = file_inst.resolvePath(STRING_Path_and_Name_of_File);
			}
			
			// save status, if file_inst exists
			OBJECT_Result['exists'] = file_inst.exists;
			
			// file_inst type detection
			if(file_inst.isDirectory)
			{
				OBJECT_Result['type'] = 'directory';
			}
			else
			{
				OBJECT_Result['type'] = 'file_inst';
			}
			
			if(file_inst.exists && file_inst.isDirectory == false)
			{
				// var fileStream:FileStream = new FileStream(); // was replaced by this.
	
				if(STRING_synchronous_or_asynchronous == 'synchronous')
				{
					this.open(file_inst, FileMode.READ);
				}
				if(STRING_synchronous_or_asynchronous == 'asynchronous')
				{
					this.openAsync(file_inst, FileMode.READ);
				}
	
				var STRING_temp:String = this.readUTFBytes(this.bytesAvailable);
				OBJECT_Result['string'] = STRING_temp;
				
				var ARRAY_temp:Array = STRING_temp.split('\n');
				OBJECT_Result['lines'] = ARRAY_temp.slice();

				if(STRING_synchronous_or_asynchronous == 'synchronous')
				{
					this.close();
				}
				if(STRING_synchronous_or_asynchronous == 'asynchronous')
				{
					// do not close 				this.close();
				}
	
				// Call the close() method of the FileStream object when you are done working with the file_inst.
				// This makes the file_inst available to other applications.
			}
			
			return OBJECT_Result;
		}

		/** reads a FileObject pointing to a utf-8 text file_inst
		 * file_inst
		 * 		if one has allready a File-Object
		 * 		then only pass this file_inst object 
		 * 		and the function tries to read it as a utf8 text file_inst.
		 * **/
		public function READ_UTF8_fromFile(file_inst:File,STRING_synchronous_or_asynchronous:String = 'synchronous'):Object
		{
			var OBJECT_Result:Object = {string:'',lines:new Array(),exists:Boolean,type:''};
			
			// save status, if file_inst exists
			OBJECT_Result['exists'] = file_inst.exists;
			
			// file_inst type detection
			if(file_inst.isDirectory)
			{
				OBJECT_Result['type'] = 'directory';
			}
			else
			{
				OBJECT_Result['type'] = 'file_inst';
			}
			
			if(file_inst.exists && file_inst.isDirectory == false)
			{
				// var fileStream:FileStream = new FileStream(); // was replaced by this.
	
				if(STRING_synchronous_or_asynchronous == 'synchronous')
				{
					this.open(file_inst, FileMode.READ);
				}
				if(STRING_synchronous_or_asynchronous == 'asynchronous')
				{
					this.openAsync(file_inst, FileMode.READ);
				}
	
				var STRING_temp:String = this.readUTFBytes(this.bytesAvailable);
				OBJECT_Result['string'] = STRING_temp;
				
				var ARRAY_temp:Array = STRING_temp.split('\n');
				OBJECT_Result['lines'] = ARRAY_temp.slice();
				
				if(STRING_synchronous_or_asynchronous == 'synchronous')
				{
					this.close();
				}
				if(STRING_synchronous_or_asynchronous == 'asynchronous')
				{
					// do not close 				this.close();
				}
				// Call the close() method of the FileStream object when you are done working with the file_inst.
				// This makes the file_inst available to other applications.
			}
			
			return OBJECT_Result;
		}
		
		/** if this is allready an existing FileStream-Object pointing to a a FileObject pointing to a utf-8 text file_inst 
		 * than this functions reads lines from it and returns them inside a object.
		 * **/
		public function FUNCTION_FILE_readUTF8(STRING_synchronous_or_asynchronous:String = 'asynchronous'):Object // FILESTREAM_instance:FileStream
		{
			var OBJECT_Result:Object = {string:'',lines:new Array(),exists:true,type:''};
			
			if(this != null)
			{
				if(this.bytesAvailable != 0) // not yet completely loaded
				{
					var STRING_temp:String = this.readUTFBytes(this.bytesAvailable);
					OBJECT_Result['string'] = STRING_temp;
					
					var ARRAY_temp:Array = STRING_temp.split('\n');
					OBJECT_Result['lines'] = ARRAY_temp.slice();
					
					if(STRING_synchronous_or_asynchronous == 'synchronous') // || this.bytesAvailable == 0) // if either one is reading synchronous or one has allready loaded all data -> close the file_inst -> make it available for other processes
					{
						this.close();
					}
					if(STRING_synchronous_or_asynchronous == 'asynchronous')
					{
						// do not close 				this.close();
					}
					// DO NOT HERE, will be called by caller. Call the close() method of the FileStream object when you are done working with the file_inst.
					// This makes the file_inst available to other applications.
				}
			}
			else
			{
				OBJECT_Result = null;
			}

			return OBJECT_Result;
		}
		
		/** creates a new text file_inst
		 * INPUT:
		 * 	ARRAY_content_lines
		 * 		an array containing a line-wise string-perspective of one's file_inst that one wants to save to file_inst.
		 * 
		 *  STIRNG_content
		 *      the string that one wants to save to file_inst 
		 * **/
		public function FUNCTION_write_new_file():void
		{
			var file_inst:File = new File('test.txt');
	
			// var fileStream:FileStream = new FileStream(); // replaces by this.
			this.open(file_inst, FileMode.WRITE); // writes a new file_inst calles file_inst
			this.close();
			// Call the close() method of the FileStream object when you are done working with the file_inst.
			// This makes the file_inst available to other applications.
		}
	}
}